<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- definetypes.qdoc -->
  <title>Defining QML 类型s from C++ | Qt QML 5.12.3</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td ><a href="../qtdoc/index.html">Qt 5.12</a></td><td ><a href="qtqml-index.html">Qt QML</a></td><td >Defining QML 类型s from C++</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtqml-index.html">Qt 5.12.3 参考指南</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">目录</a></h3>
<ul>
<li class="level1"><a href="#registering-c-types-with-the-qml-type-system">在QML类型系统中注册C++类型</a></li>
<li class="level2"><a href="#registering-an-instantiable-object-type">注册一个实例化对象类型</a></li>
<li class="level2"><a href="#registering-non-instantiable-types">注册非实例化类型</a></li>
<li class="level2"><a href="#type-revisions-and-versions">类型修订和版本</a></li>
<li class="level2"><a href="#registering-extension-objects">注册扩展对象</a></li>
<li class="level1"><a href="#defining-qml-specific-types-and-attributes">定义特定于QMLl的类型和属性</a></li>
<li class="level2"><a href="#providing-attached-properties">提供附加属性</a></li>
<li class="level2"><a href="#property-modifier-types">属性修改器类型</a></li>
<li class="level2"><a href="#specifying-default-properties-for-qml-object-types">为QML对象类型指定默认属性</a></li>
<li class="level2"><a href="#defining-visual-items-with-the-qt-quick-module">使用Qt Quick模块定义可视化项</a></li>
<li class="level1"><a href="#receiving-notifications-for-object-initialization">接收对象初始化通知</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">从C++中定义QML类型</h1>
<span class="subtitle"></span>
<!-- $$$qtqml-cppintegration-definetypes.html-description -->
<div class="descr"> <a name="details"></a>
<p>当使用C++代码扩展QML时，可以在QML类型系统中注册一个C++类，使该类能够用作QML代码中的数据类型。虽然任何<a href="../qtcore/qobject.html">QObject</a>派生类的属性、方法和信号都可以从QML访问，正如在<a href="qtqml-cppintegration-exposecppattributes.html">将C++类型的属性公开给QML</a>中讨论的那样，但是在向类型系统注册之前，此类不能用作QML的数据类型。此外，注册还可以提供其他功能，比如允许将类用作<a href="qtqml-typesystem-objecttypes.html">QML对象类型</a>的实例化，或者允许从QML导入和使用该类的单例实例。</p>
<p>此外，<a href="qtqml-index.html">Qt QML</a>模块提供了实现特定于QML的特性的机制，比如C++中的<i>附加属性</i> 和 <i>默认属性</i> 。</p>
<p>(注意，本文档中涉及的许多重要概念都在<a href="qtqml-tutorials-extending-qml-example.html">用C++编写QML扩展</a> 教程中进行了演示。)</p>
<a name="registering-c-types-with-the-qml-type-system"></a>
<h2 id="registering-c-types-with-the-qml-type-system">在QML类型系统中注册C++类型</h2>
<p>可以在QML类型系统中注册一个<a href="../qtcore/qobject.html">QObject</a>派生类，以使该类型能够在QML代码中用作数据类型。</p>
<p>该引擎允许注册可实例化和不可实例化类型。注册一个实例化类型使C++类可以用作QML对象类型的定义，从而允许在QML代码的对象声明中使用它来创建这种类型的对象。注册还为引擎提供了额外的类型元数据，支持将类型(以及该类声明的任何枚举)用作属性值、方法参数和返回值的数据类型，以及QML和C++之间交换的信号参数。</p>
<p>以这种方式注册一个非实例化类型也可以将该类注册为数据类型，但是不能将该类型用作QML对象类型的实例化。这很有用，例如，如果一个类型具有应该公开给QML的枚举，但是类型本身不应该是可实例化的。</p>
<p>有关选择向QML公开C++类型的正确方法的快速指南，请参见<a href="qtqml-cppintegration-overview.html#choosing-the-correct-integration-method-between-c-and-qml">选择C++和QML之间的正确集成方法</a>。</p>
<a name="registering-an-instantiable-object-type"></a>
<h3 >注册一个实例化对象类型</h3>
<p><b>任何<a href="../qtcore/qobject.html">QObject</a>t派生的C++类都可以注册为<a href="qtqml-typesystem-objecttypes.html">QML对象类型</a>的定义。</b> 一旦向QML类型系统注册了类，就可以像QML代码中的任何其他对象类型一样声明和实例化该类。 旦创建，就可以从QML操作类实例;正如<a href="qtqml-cppintegration-exposecppattributes.html">向QML公开C++类型的属性</a> 所解释的那样，任何<a href="../qtcore/qobject.html">QObject</a>派生类的属性、方法和信号都可以从QML代码访问。</p>
<p>要将<a href="../qtcore/qobject.html">QObject</a>派生的类注册为可实例化的QML对象类型，请调用<a href="qqmlengine.html#qmlRegisterType">qmlRegisterType</a>()将该类注册为QML类型到特定的类型名称空间中。然后，客户端可以导入该名称空间以使用该类型。</p>
<p>例如，假设有一个带有<code>author</code> 和 <code>creationDate</code>属性的<code>Message</code>类:</p>
<pre class="cpp">

  <span class="keyword">class</span> Message : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>
  {
      Q_OBJECT
      Q_PROPERTY(<span class="type"><a href="../qtcore/qstring.html">QString</a></span> author READ author WRITE setAuthor NOTIFY authorChanged)
      Q_PROPERTY(<span class="type"><a href="../qtcore/qdatetime.html">QDateTime</a></span> creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
  <span class="keyword">public</span>:
      <span class="comment">// ...</span>
  };

</pre>
<p>可以使用适当的类型名称空间和版本号调用<a href="qqmlengine.html#qmlRegisterType">qmlRegisterType</a>()注册此类型。例如，要使类型在1.0版本的<code>com.mycompany.messaging</code>名称空间中可用:</p>
<pre class="cpp">

  qmlRegisterType<span class="operator">&lt;</span>Message<span class="operator">&gt;</span>(<span class="string">&quot;com.mycompany.messaging&quot;</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="string">&quot;Message&quot;</span>);

</pre>
<p>该类型可用于QML<a href="qtqml-syntax-basics.html#object-declarations">对象声明</a>中，其属性可读可写，如下例所示:</p>
<pre class="qml">

  import com.mycompany.messaging 1.0

  <span class="type">Message</span> {
      <span class="name">author</span>: <span class="string">&quot;Amelie&quot;</span>
      <span class="name">creationDate</span>: new <span class="name">Date</span>()
  }

</pre>
<a name="registering-non-instantiable-types"></a>
<h3 >注册非实例化类型</h3>
<p>有时候，<a href="../qtcore/qobject.html">QObject</a>派生的类可能需要在QML类型系统中注册，但不是作为可实例化的类型。例如，如果一个C++类:</p>
<ul>
<li>接口类型是否不能实例化</li>
<li>是否不需要向QML公开基类类型</li>
<li>声明一些应该可以从QML访问的枚举，但否则不应该是可实例化的</li>
<li>是应该通过单例实例提供给QML的类型，而不应该从QML实例化</li>
</ul>
<p><a href="qtqml-index.html">Qt QML</a>模块提供了几种注册非实例化类型的方法:</p>
<ul>
<li><a href="qqmlengine.html#qmlRegisterType">qmlRegisterType</a>() (没有参数)注册了一个C++类型，该类型不能实例化，也不能从QML引用。这使引擎能够强制从QML实例化任何继承类型。</li>
<li><a href="qqmlengine.html#qmlRegisterInterface">qmlRegisterInterface</a>() 注册现有Qt接口类型。类型不能从QML实例化，并且不能用它声明QML属性。不过，使用QML中此类C++属性将执行预期的接口转换。</li>
<li><a href="qqmlengine.html#qmlRegisterUncreatableType">qmlRegisterUncreatableType</a>() 注册了一个命名的C++类型，该类型不能实例化，但是应该被标识为QML类型系统的类型。如果类型的枚举或附加属性应该可以从QML访问，但类型本身不应该是可实例化的，那么这将非常有用。</li>
<li><a href="qqmlengine.html#qmlRegisterSingletonType">qmlRegisterSingletonType</a>() 注册了一个可以从QML导入的单例类型，如下所述。</li>
</ul>
<p>注意，所有在QML类型系统中注册的C++类型都必须是<a href="../qtcore/qobject.html">QObject</a>派生的，即使它们是不可实例化</p>
<a name="registering-singleton-objects-with-a-singleton-type"></a>
<h4 >用单例类型注册单例对象</h4>
<p>单例类型允许在名称空间中公开属性、信号和方法，而不需要客户机手动实例化对象实例。<a href="../qtcore/qobject.html">QObject</a> 单例类型是提供功能或全局属性值的一种有效且方便的方法。</p>
<p>注意，单例类型没有关联的<a href="qqmlcontext.html">QQmlContext</a> t，因为它们在引擎中的所有上下文中共享。 <a href="../qtcore/qobject.html">QObject</a> 单例类型实例由<a href="qqmlengine.html">QQmlEngine</a>造并拥有，当引擎被销毁时将被销毁。</p>
<p><a href="../qtcore/qobject.html">QObject</a>单例类型可以以类似于任何其他 <a href="../qtcore/qobject.html">QObject</a> 或实例化类型的方式进行交互，但是只存在一个(构造并拥有的引擎)实例，而且必须使用类型名称而不是id来引用它。可以绑定<a href="../qtcore/qobject.html">QObject</a>单例类型的Q_PROPERTY，也可以在信号处理程序表达式中使用<a href="../qtcore/qobject.html">QObject</a>模块API的<a href="../qtcore/qobject.html#Q_INVOKABLE">Q_INVOKABLE</a>函数。 </p>
<p>注册后，可以导入 <a href="../qtcore/qobject.html">QObject</a> 单例类型，并像公开给QML的任何其他<a href="../qtcore/qobject.html">QObject</a> 实例一样使用它。下面的例子假设一个<a href="../qtcore/qobject.html">QObject</a> 单例类型在1.0版本中注册到“MyThemeModule”名称空间中，该<a href="../qtcore/qobject.html">QObject</a> 有一个<a href="../qtgui/qcolor.html">QColor</a>“color”<a href="../qtcore/qobject.html#Q_PROPERTY">Q_PROPERTY</a>:</p>
<pre class="qml">

  import MyThemeModule 1.0 as Theme

  <span class="type"><a href="../qtquick/qml-qtquick-rectangle.html">Rectangle</a></span> {
      <span class="name">color</span>: <span class="name">Theme</span>.<span class="name">color</span> <span class="comment">// binding.</span>
  }

</pre>
<p><a href="qjsvalue.html">QJSValue</a>也可以公开为单例类型，但是客户端应该知道不能绑定这种单例类型的属性。</p>
<p>有关如何实现和注册新单例类型以及如何使用现有单例类型的更多信息，请参见<a href="qqmlengine.html#qmlRegisterSingletonType">qmlRegisterSingletonType</a>() 。</p>
<p><b>注意: </b>QML中注册类型的枚举值应该以大写字母开头。</p><a name="type-revisions-and-versions"></a>
<h3 >类型修订和版本</h3>
<p>许多类型注册函数都要求为已注册的类型指定版本。类型修订和版本允许新版本中存在新的属性或方法，同时与以前的版本保持兼容。</p>
<p>考虑以下两个QML文件:</p>
<pre class="cpp">

  <span class="comment">// main.qml</span>
  import <span class="type">QtQuick</span> <span class="number">1.0</span>

  Item {
      id: root
      MyType {}
  }

</pre>
<pre class="cpp">

  <span class="comment">// MyType.qml</span>
  import MyTypes <span class="number">1.0</span>

  CppType {
      value: root<span class="operator">.</span>x
  }

</pre>
<p>其中<code>CppType</code>映射到C++类<code>CppType</code>。</p>
<p>如果CppType的作者在其类型定义的新版本中向CppType添加<code>root</code>属性。 那么<code>root.x</code>现在将解析为一个不同的值，因为<code>root</code> 也是顶层组件的 <code>id</code>。作者可以指定新的<code>root</code>属性可以从特定的次要版本中获得。这允许在不破坏现有程序的情况下向现有类型添加新属性和特性。</p>
<p>REVISION标记用于标记类型的修订1中添加的<code>root</code>属性。方法，如<a href="../qtcore/qobject.html#Q_INVOKABLE">Q_INVOKABLE</a>的，信号和插槽也可以标记为使用<code>Q_REVISION(x)</code>宏的修订:</p>
<pre class="cpp">

  <span class="keyword">class</span> CppType : <span class="keyword">public</span> BaseType
  {
      Q_OBJECT
      Q_PROPERTY(<span class="type">int</span> root READ root WRITE setRoot NOTIFY rootChanged REVISION <span class="number">1</span>)

  <span class="keyword">signals</span>:
      Q_REVISION(<span class="number">1</span>) <span class="type">void</span> rootChanged();
  };

</pre>
<p>要将新类修订注册到特定版本，使用以下函数:</p>
<pre class="cpp">

  <span class="keyword">template</span><span class="operator">&lt;</span><span class="keyword">typename</span> T<span class="operator">,</span> <span class="type">int</span> metaObjectRevision<span class="operator">&gt;</span>
  <span class="type">int</span> qmlRegisterType(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri<span class="operator">,</span> <span class="type">int</span> versionMajor<span class="operator">,</span> <span class="type">int</span> versionMinor<span class="operator">,</span> <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>qmlName)

</pre>
<p>为<code>MyTypes 1.1</code>注册<code>CppType</code> 版本1：</p>
<pre class="cpp">

  qmlRegisterType<span class="operator">&lt;</span>CppType<span class="operator">,</span><span class="number">1</span><span class="operator">&gt;</span>(<span class="string">&quot;MyTypes&quot;</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="string">&quot;CppType&quot;</span>)

</pre>
<p><code>root</code> 仅在导入<code>MyTypes</code>1.1版本时可用。</p>
<p>出于同样的原因，在以后的版本中引入的新类型应该使用<a href="qqmlengine.html#qmlRegisterType">qmlRegisterType</a>的次要版本参数。</p>
<p>该语言的这一特性允许在不破坏现有应用程序的情况下进行行为更改。因此，QML模块的作者应该始终记住记录在次要版本之间发生了什么变化，QML模块的用户应该在部署更新的导入语句之前检查他们的应用程序是否仍然正确运行。</p>
<p>您还可以使用<a href="qqmlengine.html#qmlRegisterRevision">qmlRegisterRevision</a>() 函数注册您的类型依赖的基类的修订:</p>
<pre class="cpp">

  <span class="keyword">template</span><span class="operator">&lt;</span><span class="keyword">typename</span> T<span class="operator">,</span> <span class="type">int</span> metaObjectRevision<span class="operator">&gt;</span>
  <span class="type">int</span> qmlRegisterRevision(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri<span class="operator">,</span> <span class="type">int</span> versionMajor<span class="operator">,</span> <span class="type">int</span> versionMinor)

  <span class="keyword">template</span><span class="operator">&lt;</span><span class="keyword">typename</span> T<span class="operator">,</span> <span class="type">int</span> metaObjectRevision<span class="operator">&gt;</span>
  <span class="type">int</span> qmlRegisterUncreatableType(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri<span class="operator">,</span> <span class="type">int</span> versionMajor<span class="operator">,</span> <span class="type">int</span> versionMinor<span class="operator">,</span> <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>qmlName<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="../qtcore/qstring.html">QString</a></span><span class="operator">&amp;</span> reason)

  <span class="keyword">template</span><span class="operator">&lt;</span><span class="keyword">typename</span> T<span class="operator">,</span> <span class="keyword">typename</span> E<span class="operator">,</span> <span class="type">int</span> metaObjectRevision<span class="operator">&gt;</span>
  <span class="type">int</span> qmlRegisterExtendedUncreatableType(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri<span class="operator">,</span> <span class="type">int</span> versionMajor<span class="operator">,</span> <span class="type">int</span> versionMinor<span class="operator">,</span> <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>qmlName<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="../qtcore/qstring.html">QString</a></span><span class="operator">&amp;</span> reason)

</pre>
<p>例如，如果更改了<code>BaseType</code>，现在有一个修订1，您可以指定您的类型使用新的修订:</p>
<pre class="cpp">

  qmlRegisterRevision<span class="operator">&lt;</span>BaseType<span class="operator">,</span><span class="number">1</span><span class="operator">&gt;</span>(<span class="string">&quot;MyTypes&quot;</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">1</span>);

</pre>
<p>这在从其他作者提供的基类派生时很有用，例如从Qt Quick模块扩展类时。</p>
<p><b>注意:</b>QML引擎不支持对分组和附加属性对象的属性或信号进行修订。</p><a name="registering-extension-objects"></a>
<h3 >注册扩展对象</h3>
<p>当将现有的类和技术集成到QML中时，API常常需要进行调整以更好地适应声明性环境。虽然最好的结果通常是通过直接修改原始类获得的，但是如果这是不可能的，或者由于其他一些问题而变得复杂，扩展对象允许有限的扩展可能性，而不需要直接修改。</p>
<p><i>扩展对象</i> 向现有类型添加附加属性。扩展对象只能添加属性，而不能添加信号或方法。扩展类型定义允许程序员在注册类时提供一个额外的类型，称为<i>扩展类型/i>。当从QML中使用属性时，这些属性将透明地与原始目标类合并。例如:</p>
<pre class="qml">

  <span class="type">QLineEdit</span> {
      <span class="name">leftMargin</span>: <span class="number">20</span>
  }

</pre>
<p><code>leftMargin</code> leftMargin属性是添加到现有C++类型<a href="../qtwidgets/qlineedit.html">QLineEdit</a>的新属性，无需修改其源代码。</p>
<p><a href="qqmlengine.html#qmlRegisterExtendedType">qmlRegisterExtendedType()</a> 函数用于注册扩展类型。注意，它有两种形式。</p>
<pre class="cpp">

  <span class="keyword">template</span><span class="operator">&lt;</span><span class="keyword">typename</span> T<span class="operator">,</span> <span class="keyword">typename</span> ExtendedT<span class="operator">&gt;</span>
  <span class="type">int</span> qmlRegisterExtendedType(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri<span class="operator">,</span> <span class="type">int</span> versionMajor<span class="operator">,</span> <span class="type">int</span> versionMinor<span class="operator">,</span> <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>qmlName)

  <span class="keyword">template</span><span class="operator">&lt;</span><span class="keyword">typename</span> T<span class="operator">,</span> <span class="keyword">typename</span> ExtendedT<span class="operator">&gt;</span>
  <span class="type">int</span> qmlRegisterExtendedType()

</pre>
<p>应该使用此函数而不是常规的<code>qmlRegisterType()</code> 变体。参数与对应的非扩展注册函数相同，但ExtendedT参数是扩展对象的类型。</p>
<p>扩展类是一个常规的<a href="../qtcore/qobject.html">QObject</a>，其构造函数接受<a href="../qtcore/qobject.html">QObject</a>指针。但是，扩展类的创建将延迟到访问第一个扩展属性之后。创建扩展类并将目标对象作为父对象传入。当访问原始对象上的属性时，将使用扩展对象上的对应属性。</p>
<p><a href="qtqml-referenceexamples-extended-example.html">扩展对象示例</a> 演示了扩展对象的用法。</p>
<a name="defining-qml-specific-types-and-attributes"></a>
<h2 id="defining-qml-specific-types-and-attributes">定义特定于QMLl的类型和属性</h2>
<a name="providing-attached-properties"></a>
<h3 >提供附加属性</h3>
<p>在QML语言语法中，有一个<a href="qtqml-syntax-objectattributes.html#attached-properties-and-attached-signal-handlers"><i>附加属性</i> 和 <i>附加信号处理程序</i></a>的概念，它们是附加到对象上的附加属性。本质上，这些属性是由<i>附加类型</i>实现和提供的，这些属性可以 <i>附加</i> 到另一种类型的对象上。这与由对象类型本身(或对象的继承类型)提供的普通对象属性形成了对比。</p>
<p>例如，下面的<a href="../qtquick/qml-qtquick-item.html">Item</a>使用附加属性和附加处理程序:</p>
<pre class="qml">

  import QtQuick 2.0

  <span class="type"><a href="../qtquick/qml-qtquick-item.html">Item</a></span> {
      <span class="name">width</span>: <span class="number">100</span>; <span class="name">height</span>: <span class="number">100</span>

      <span class="name">focus</span>: <span class="number">true</span>
      <span class="name">Keys</span>.enabled: <span class="number">false</span>
      <span class="name">Keys</span>.onReturnPressed: <span class="name">console</span>.<span class="name">log</span>(<span class="string">&quot;Return key was pressed&quot;</span>)
  }

</pre>
<p>在这里，<a href="../qtquick/qml-qtquick-item.html">Item</a>对象能够访问和设置<code>Keys.enabled</code> 和 <code>Keys.onReturnPressed</code>的值。这允许<a href="../qtquick/qml-qtquick-item.html">Item</a> 对象访问这些额外的属性，作为对其现有属性的扩展。</p>
<a name="steps-for-implementing-attached-objects"></a>
<h4 >实现附加对象的步骤</h4>
<p>在考虑上述例子时，涉及到几个方面:</p>
<ul>
<li>有一个匿名<i>附加对象类型</i>的实例，带有一个<code>enabled</code> 和一个 <code>returnPressed</code>信号，该实例已附加到<a href="../qtquick/qml-qtquick-item.html">Item</a> 对象，以使其能够访问和设置这些属性。</li>
<li><a href="../qtquick/qml-qtquick-item.html">Item</a> 对象是 <i>attachee</i>，已将<i>附加对象类型</i>的实例附加到其上。</li>
<li><a href="../qtquick/qml-qtquick-keys.html">Keys</a> 是<i>附加类型</i>，它为<i>attachee</i> 提供一个命名限定符“键”，通过它可以访问<i>附加对象类型</i>的属性。</li>
</ul>
<p>当QML引擎处理此代码时，它创建附加对象类型的单个实例，并将此实例附加到<a href="../qtquick/qml-qtquick-item.html">Item</a>对象，从而为其提供对实例的<code>enabled</code> 和 <code>returnPressed</code> 属性的访问。</p>
<p>通过为<i>附加对象类型</i> 和 <i>附加类型</i>提供类，可以从C++实现提供附加对象的机制。对于 <i>附加对象类型</i>，提供一个<a href="../qtcore/qobject.html">QObject</a>t派生类，该类定义要使<i>attachee</i>对象可访问的属性。 对于<i>附加类型</i>，提供一个<a href="../qtcore/qobject.html">QObject</a>派生类:</p>
<ul>
<li>使用以下签名实现静态qmlAttachedProperties():<pre class="cpp">

  <span class="keyword">static</span> <span class="operator">&lt;</span>AttachedPropertiesType<span class="operator">&gt;</span> <span class="operator">*</span>qmlAttachedProperties(<span class="type"><a href="../qtcore/qobject.html">QObject</a></span> <span class="operator">*</span>object);

</pre>
<p>方法应返回附加对象类型的实例</i>。</p>
<p>QML引擎调用此方法，以便将附加对象类型的实例附加到<code>object</code>参数指定的<i>attachee</i> 。虽然不是严格要求，但通常这种方法实现将返回的实例父类化为<code>object</code>，以防止内存泄漏。</p>
<p>对于每个attachee对象实例，引擎最多只调用此方法一次，因为引擎缓存返回的实例指针，以便后续的附加属性访问。因此，在销毁attachee <code>object</code> 之前，不能删除附加对象。</p>
</li>
<li>通过使用QML_HAS_ATTACHED_PROPERTIES标志调用<a href="qqmlengine.html#QML_DECLARE_TYPEINFO">QML_DECLARE_TYPEINFO</a>() 宏，将其声明为附加类型</li>
</ul>
<a name="implementing-attached-objects-an-example"></a>
<h4 >实现附加对象:一个例子</h4>
<p>例如，以<a href="qtqml-cppintegration-definetypes.html#registering-an-instantiable-object-type">前面示例</a>中描述的<code>Message</code> 类型为例:</p>
<pre class="cpp">

  <span class="keyword">class</span> Message : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>
  {
      Q_OBJECT
      Q_PROPERTY(<span class="type"><a href="../qtcore/qstring.html">QString</a></span> author READ author WRITE setAuthor NOTIFY authorChanged)
      Q_PROPERTY(<span class="type"><a href="../qtcore/qdatetime.html">QDateTime</a></span> creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
  <span class="keyword">public</span>:
      <span class="comment">// ...</span>
  };

</pre>
<p>假设有必要在<code>Message</code>上将信号发布到消息板时触发该信号，并跟踪消息板上的消息何时过期。由于将这些属性直接添加到<code>Message</code>没有任何意义，因为这些属性与消息板上下文更相关，所以可以将它们实现为<code>Message</code>对象上的<i>attached</i>属性，这些属性是通过 object that are provided through a &quot;MessageBoard&quot; 限定符提供的。根据上文所述的概念，这里涉及的各方是:</p>
<ul>
<li>匿名 <i>附加对象类型</i>的实例，它提供<code>published</code> 的信号和已过期的属性。此类型由下面的<code>MessageBoardAttachedType</code>实现/li>
<li>一个<code>Message</code> 对象，它将是<i>attachee</i></li>
<li><code>MessageBoard</code> 类型，它是<code>Message</code> 对象用来访问附加属性的<i>附加类型</i> </li>
</ul>
<p>下面是一个示例实现。首先，需要有一个<i>附加的对象类型</i> 与必要的属性和信号，将访问<i>attachee</i>:</p>
<pre class="cpp">

  <span class="keyword">class</span> MessageBoardAttachedType : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>
  {
      Q_OBJECT
      Q_PROPERTY(bool expired READ expired WRITE expired NOTIFY expiredChanged)
  <span class="keyword">public</span>:
      MessageBoardAttachedType(<span class="type"><a href="../qtcore/qobject.html">QObject</a></span> <span class="operator">*</span>parent);
      bool expired() <span class="keyword">const</span>;
      <span class="type">void</span> setExpired(bool expired);
  <span class="keyword">signals</span>:
      <span class="type">void</span> published();
      <span class="type">void</span> expiredChanged();
  };

</pre>
<p>然后，<i>附加类型</i>, <code>MessageBoard</code>必须声明一个<code>qmlAttachedProperties()</code> 方法，该方法返回由MessageBoardAttachedType 实现的<i>附加对象类型</i>实例。另外，<code>Message</code>板必须通过<a href="qqmlengine.html#QML_DECLARE_TYPEINFO">QML_DECLARE_TYPEINFO</a>()宏声明为附加类型:</p>
<pre class="cpp">

  <span class="keyword">class</span> MessageBoard : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>
  {
      Q_OBJECT
  <span class="keyword">public</span>:
      <span class="keyword">static</span> MessageBoard <span class="operator">*</span>qmlAttachedProperties(<span class="type"><a href="../qtcore/qobject.html">QObject</a></span> <span class="operator">*</span>object)
      {
          <span class="keyword">return</span> <span class="keyword">new</span> MessageBoardAttachedType(object);
      }
  };
  QML_DECLARE_TYPEINFO(MessageBoard<span class="operator">,</span> QML_HAS_ATTACHED_PROPERTIES)

</pre>
<p>现在，<code>Message</code> 类型可以访问附加对象类型的属性和信号:</p>
<pre class="qml">

  <span class="type">Message</span> {
      <span class="name">author</span>: <span class="string">&quot;Amelie&quot;</span>
      <span class="name">creationDate</span>: new <span class="name">Date</span>()

      <span class="name">MessageBoard</span>.expired: <span class="name">creationDate</span> <span class="operator">&lt;</span> new <span class="name">Date</span>(<span class="string">&quot;January 01, 2015 10:45:00&quot;</span>)
      <span class="name">MessageBoard</span>.onPublished: <span class="name">console</span>.<span class="name">log</span>(<span class="string">&quot;Message by&quot;</span>, <span class="name">author</span>, <span class="string">&quot;has been
  published!&quot;</span>)
  }

</pre>
<p>此外，C++实现可以通过调用<a href="qqmlengine.html#qmlAttachedPropertiesObject">qmlAttachedPropertiesObject</a>() 函数访问附加到任何对象的附加对象实例。</p>
<p>例如:</p>
<pre class="cpp">

  Message <span class="operator">*</span>msg <span class="operator">=</span> someMessageInstance();
  MessageBoardAttachedType <span class="operator">*</span>attached <span class="operator">=</span>
          qobject_cast<span class="operator">&lt;</span>MessageBoardAttachedType<span class="operator">*</span><span class="operator">&gt;</span>(qmlAttachedPropertiesObject<span class="operator">&lt;</span>MessageBoard<span class="operator">&gt;</span>(msg));

  <a href="../qtcore/qtglobal.html#qDebug">qDebug</a>() <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;Value of MessageBoard.expired:&quot;</span> <span class="operator">&lt;</span><span class="operator">&lt;</span> attached<span class="operator">-</span><span class="operator">&gt;</span>expired();

</pre>
<a name="property-modifier-types"></a>
<h3 >属性修改器类型</h3>
<p>属性修改器类型是一种特殊的QML对象类型。属性修改器类型实例影响其应用于的属性(QML对象实例的属性)。有两种不同的属性修改器类型:</p>
<ul>
<li>属性值写入拦截器</li>
<li>属性值源</li>
</ul>
<p>属性值写入拦截器可用于筛选或修改写入属性的值。目前，惟一受支持的属性值写拦截器是<code>QtQuick</code>导入提供的<a href="../qtquick/qml-qtquick-behavior.html">Behavior</a>类型。</p>
<p>属性值源可用于随时间自动更新属性值。客户端可以定义自己的属性值源类型。<code>QtQuick</code>导入提供的各种<a href="../qtquick/qtquick-statesanimations-animations.html">属性动画</a>类型都是属性值源的示例。</p>
<p>属性修改器类型实例可以通过“<propertyName>上的<ModifierType>”语法创建并应用于QML对象的属性，如下例所示:</p>
<pre class="qml">

  import QtQuick 2.0

  <span class="type"><a href="../qtquick/qml-qtquick-item.html">Item</a></span> {
      <span class="name">width</span>: <span class="number">400</span>
      <span class="name">height</span>: <span class="number">50</span>

      <span class="type"><a href="../qtquick/qml-qtquick-rectangle.html">Rectangle</a></span> {
          <span class="name">width</span>: <span class="number">50</span>
          <span class="name">height</span>: <span class="number">50</span>
          <span class="name">color</span>: <span class="string">&quot;red&quot;</span>

          NumberAnimation on <span class="name">x</span> {
              <span class="name">from</span>: <span class="number">0</span>
              <span class="name">to</span>: <span class="number">350</span>
              <span class="name">loops</span>: <span class="name">Animation</span>.<span class="name">Infinite</span>
              <span class="name">duration</span>: <span class="number">2000</span>
          }
      }
  }

</pre>
<p>客户端可以注册自己的属性值源类型，但目前还不能编写属性值拦截器。</p>
<a name="property-value-sources"></a>
<h4 >属性值源</h4>
<p><i>属性值源</i> 是QML类型，可以使用<code>&lt;property&gt;语法上的&lt;PropertyValueSource&gt;</code> 随时间自动更新属性值。例如，<code>QtQuick</code>模块提供的各种<a href="../qtquick/qtquick-statesanimations-animations.html">属性动画</a>类型都是属性值源的示例。</p>
<p>属性值源可以用C++实现，方法是子类化<a href="qqmlpropertyvaluesource.html">QQmlPropertyValueSource</a>并提供一个实现，该实现可以随着时间的推移向属性写入不同的值。当使用QML中的 <code>&lt;property&gt;语法上的&lt;PropertyValueSource&gt; </code>将属性值源应用于属性时，引擎将提供对该属性的引用，以便可以更新属性值。</p>
<p>例如，假设有一个<code>RandomNumberGenerator</code>类可用作属性值源，以便在应用于QML属性时，它将每500毫秒将属性值更新为一个不同的随机数。此外，可以为这个随机数生成器提供一个maxValue。这个类可以实现如下:</p>
<pre class="cpp">

  <span class="keyword">class</span> RandomNumberGenerator : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span><span class="operator">,</span> <span class="keyword">public</span> <span class="type"><a href="qqmlpropertyvaluesource.html">QQmlPropertyValueSource</a></span>
  {
      Q_OBJECT
      Q_INTERFACES(<span class="type"><a href="qqmlpropertyvaluesource.html">QQmlPropertyValueSource</a></span>)
      Q_PROPERTY(<span class="type">int</span> maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged);
  <span class="keyword">public</span>:
      RandomNumberGenerator(<span class="type"><a href="../qtcore/qobject.html">QObject</a></span> <span class="operator">*</span>parent)
          : <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>(parent)<span class="operator">,</span> m_maxValue(<span class="number">100</span>)
      {
          <span class="type"><a href="../qtcore/qobject.html">QObject</a></span><span class="operator">::</span>connect(<span class="operator">&amp;</span>m_timer<span class="operator">,</span> SIGNAL(timeout())<span class="operator">,</span> SLOT(updateProperty()));
          m_timer<span class="operator">.</span>start(<span class="number">500</span>);
      }

      <span class="type">int</span> maxValue() <span class="keyword">const</span>;
      <span class="type">void</span> setMaxValue(<span class="type">int</span> maxValue);

      <span class="keyword">virtual</span> <span class="type">void</span> setTarget(<span class="keyword">const</span> <span class="type"><a href="qqmlproperty.html">QQmlProperty</a></span> <span class="operator">&amp;</span>prop) { m_targetProperty <span class="operator">=</span> prop; }

  <span class="keyword">signals</span>:
      <span class="type">void</span> maxValueChanged();

  <span class="keyword">private</span> <span class="keyword">slots</span>:
      <span class="type">void</span> updateProperty() {
          m_targetProperty<span class="operator">.</span>write(<span class="type"><a href="../qtcore/qrandomgenerator.html">QRandomGenerator</a></span><span class="operator">::</span>global()<span class="operator">-</span><span class="operator">&gt;</span>bounded(m_maxValue));
      }

  <span class="keyword">private</span>:
      <span class="type"><a href="qqmlproperty.html">QQmlProperty</a></span> m_targetProperty;
      <span class="type"><a href="../qtcore/qtimer.html">QTimer</a></span> m_timer;
      <span class="type">int</span> m_maxValue;
  };

</pre>
<p>当QML引擎遇到使用<code>RandomNumberGenerator</code> 作为属性值源时，它调用<code>RandomNumberGenerator::setTarget()</code> 来为类型提供应用了值源的属性。当<code>RandomNumberGenerator</code> 中的内部计时器每500毫秒触发一次时，它将向指定的属性写入一个新的数值。</p>
<p>一旦<a href="../qtquick/qml-qtquick-rectangle.html">Rectangle</a>类注册到QML类型系统，就可以从QML将其用作属性值源。下面，它用于每500毫秒改变一个矩形的宽度:</p>
<pre class="qml">

  import QtQuick 2.0

  <span class="type"><a href="../qtquick/qml-qtquick-item.html">Item</a></span> {
      <span class="name">width</span>: <span class="number">300</span>; <span class="name">height</span>: <span class="number">300</span>

      <span class="type"><a href="../qtquick/qml-qtquick-rectangle.html">Rectangle</a></span> {
          RandomNumberGenerator on <span class="name">width</span> { <span class="name">maxValue</span>: <span class="number">300</span> }

          <span class="name">height</span>: <span class="number">100</span>
          <span class="name">color</span>: <span class="string">&quot;red&quot;</span>
      }
  }

</pre>
<p>在所有其他方面，属性值源都是常规的QML类型，可以有属性、信号方法等等，但是添加了使用<code>&lt;property&gt;语法上的&lt;PropertyValueSource&gt; </code>更改属性值的功能。</p>
<p>当一个属性值源对象被分配给一个属性时，QML首先尝试正常分配它，就像它是一个常规的QML类型一样。只有当分配失败时，引擎才调用<a href="qqmlpropertyvaluesource.html#setTarget">setTarget()</a>方法。这允许该类型还可以在上下文中使用，而不仅仅用作值源。</p>
<a name="specifying-default-properties-for-qml-object-types"></a>
<h3 >为QML对象类型指定默认属性</h3>
<p>注册为可实例化QML对象类型的任何<a href="../qtcore/qobject.html">QObject</a>派生类型都可以为该类型指定<i>默认属性</i> 。默认属性是如果对象的子对象没有被分配到任何特定的属性，则自动分配给它们的属性。</p>
<p>可以通过调用具有特定“DefaultProperty”值的类的<a href="../qtcore/qobject.html#Q_CLASSINFO">Q_CLASSINFO</a>() 宏来设置默认属性。例如，下面的<code>MessageBoard</code> 类将其 <code>messages</code> 属性指定为该类的默认属性:</p>
<pre class="cpp">

  <span class="keyword">class</span> MessageBoard : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>
  {
      Q_OBJECT
      Q_PROPERTY(<span class="type"><a href="qqmllistproperty.html">QQmlListProperty</a></span><span class="operator">&lt;</span>Message<span class="operator">&gt;</span> messages READ messages)
      Q_CLASSINFO(<span class="string">&quot;DefaultProperty&quot;</span><span class="operator">,</span> <span class="string">&quot;messages&quot;</span>)
  <span class="keyword">public</span>:
      <span class="type"><a href="qqmllistproperty.html">QQmlListProperty</a></span><span class="operator">&lt;</span>Message<span class="operator">&gt;</span> messages();

  <span class="keyword">private</span>:
      <span class="type"><a href="../qtcore/qlist.html">QList</a></span><span class="operator">&lt;</span>Message <span class="operator">*</span><span class="operator">&gt;</span> m_messages;
  };

</pre>
<p>这使<code>MessageBoard</code>对象的子对象可以自动分配到其<code>messages</code>属性(如果没有分配到特定属性)。例如:</p>
<pre class="qml">

  <span class="type">MessageBoard</span> {
      <span class="type">Message</span> { <span class="name">author</span>: <span class="string">&quot;Naomi&quot;</span> }
      <span class="type">Message</span> { <span class="name">author</span>: <span class="string">&quot;Clancy&quot;</span> }
  }

</pre>
<p>如果<code>messages</code> 未设置为默认属性，则必须显式地将任何<code>Message</code>对象分配给<code>messages</code>属性，如下所示:</p>
<pre class="qml">

  <span class="type">MessageBoard</span> {
      <span class="name">messages</span>: [
          <span class="type">Message</span> { <span class="name">author</span>: <span class="string">&quot;Naomi&quot;</span> },
          <span class="type">Message</span> { <span class="name">author</span>: <span class="string">&quot;Clancy&quot;</span> }
      ]
  }

</pre>
<p>(顺便提一下，<a href="../qtquick/qml-qtquick-item.html#data-prop">Item::data</a> 属性是它的默认属性。添加到此<code>data</code>属性的任何<a href="../qtquick/qml-qtquick-item.html">Item</a> 对象也会添加到<a href="../qtquick/qml-qtquick-item.html#children-prop">Item::children</a>列表中，因此使用默认属性可以声明项的可视子对象，而无需显式地将它们分配给<a href="../qtquick/qml-qtquick-item.html#children-prop">children</a>属性。) </p>
<a name="defining-visual-items-with-the-qt-quick-module"></a>
<h3 >使用Qt Quick模块定义可视化项</h3>
<p>当使用<a href="../qtquick/qtquick-index.html">Qt Quick</a>模块构建用户界面时，所有要可视化呈现的QML对象都必须派生自<a href="../qtquick/qml-qtquick-item.html">Item</a> 类型，因为它是<a href="../qtquick/qtquick-index.html">Qt Quick</a>中所有可视化对象的基类型。此<a href="../qtquick/qml-qtquick-item.html">Item</a>类型由Qt Quick模块提供的<a href="../qtquick/qquickitem.html">QQuickItem</a> C++类实现。因此，当需要用C++实现可以集成到基于QML的用户界面中的可视类型时，应该子类化该类。</p>
<p>有关更多信息，请参阅<a href="../qtquick/qquickitem.html">QQuickItem</a> 文档。此外，<a href="qtqml-tutorials-extending-qml-example.html">用C++编写QML扩展</a> 教程演示了如何在C++中实现基于<a href="../qtquick/qquickitem.html">QQuickItem</a>的可视化项目，并将其集成到基于Qt Quick-based的用户界面中。</p>
<a name="receiving-notifications-for-object-initialization"></a>
<h2 id="receiving-notifications-for-object-initialization">接收对象初始化通知</h2>
<p>对于一些自定义QML对象类型,它可能是有益的特定数据的初始化推迟到已创建的对象和它的所有属性集。例如,可能这种情况如果初始化是昂贵的,或者在初始化所有属性值之前不应该执行初始化。</p>
<p><a href="qtqml-index.html">Qt QML</a> 模块为这些目的提供了要子类化的<a href="qqmlparserstatus.html">QQmlParserStatus</a>。它定义了许多虚拟方法，这些方法在组件实例化的不同阶段被调用。要接收这些通知，C++类应该继承<a href="qqmlparserstatus.html">QQmlParserStatus</a> ，并使用<a href="../qtcore/qobject.html#Q_INTERFACES">Q_INTERFACES</a>()宏通知Qt元系统。</p>
<p>例如:</p>
<pre class="cpp">

  <span class="keyword">class</span> MyQmlType : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span><span class="operator">,</span> <span class="keyword">public</span> <span class="type"><a href="qqmlparserstatus.html">QQmlParserStatus</a></span>
  {
      Q_OBJECT
      Q_INTERFACES(<span class="type"><a href="qqmlparserstatus.html">QQmlParserStatus</a></span>)
  <span class="keyword">public</span>:
      <span class="keyword">virtual</span> <span class="type">void</span> componentComplete()
      {
          <span class="comment">// Perform some initialization here now that the object is fully created</span>
      }
  };

</pre>
</div>
<!-- @@@qtqml-cppintegration-definetypes.html -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2019 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>
